package cn.itcast.sys.service.impl;

import cn.itcast.constant.JwtClaimsConstant;
import cn.itcast.constant.MessageConstant;
import cn.itcast.constant.PasswordConstant;
import cn.itcast.constant.StatusConstant;
import cn.itcast.context.BaseContext;
import cn.itcast.exception.AccountLockedException;
import cn.itcast.exception.AccountStatusException;
import cn.itcast.exception.LoginFailedException;
import cn.itcast.exception.PasswordErrorException;
import cn.itcast.properties.JwtProperties;
import cn.itcast.result.PageBean;
import cn.itcast.result.Result;
import cn.itcast.sys.dto.EmployeeDTO;
import cn.itcast.sys.dto.EmployeeLoginDTO;
import cn.itcast.sys.dto.EmployeePageQueryDTO;
import cn.itcast.sys.mapper.EmployeeMapper;
import cn.itcast.sys.pojo.Employee;
import cn.itcast.sys.service.EmployeeService;
import cn.itcast.users.dto.PasswordEditDTO;
import cn.itcast.users.vo.EmployeeLoginVO;
import cn.itcast.utils.JwtUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class EmployeeServiceImpl implements EmployeeService {

    @Autowired
    private EmployeeMapper employeeMapper;
    @Autowired
    private JwtProperties jwtProperties;
    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 员工登录
     *
     * @param dto
     * @return
     */
    @Override
    public Result<EmployeeLoginVO> login(EmployeeLoginDTO dto) {
        ValueOperations valueOperations = redisTemplate.opsForValue();
        //1.判断账号是否存在
        Employee employee = employeeMapper.seleteByUsername(dto);
        if (employee == null) {
            throw new LoginFailedException(MessageConstant.ACCOUNT_NOT_FOUND);
        }
        //2.判断密码是否正确
        if (!employee.getPassword().equals(dto.getPassword())) {
            //累加错误次数
            Integer countError = (Integer) valueOperations.get("accountErrorCount" + dto.getUsername());
            if (countError == null) {
                valueOperations.set("accountErrorCount" + dto.getUsername(),
                        1
                        , 60, TimeUnit.SECONDS);
                countError = 1;
            } else {
                valueOperations.set("accountErrorCount" + dto.getUsername(),
                        countError + 1
                        , 0);
            }
            //初始化完成，接下来完成判断逻辑

            countError = (Integer) valueOperations.get("accountErrorCount" + dto.getUsername());
            //如果1分钟之内密码错误次数超过3次
            if (countError.equals(3)) {
                valueOperations.set("accountLocked" + dto.getUsername(), "Lock", 1, TimeUnit.HOURS);
            }
            if ("Lock".equals(valueOperations.get("accountLocked" + dto.getUsername()))) {
                //抛出账号锁定异常
                long time = valueOperations.getOperations().getExpire("accountLocked" + dto.getUsername()) / 60;
                throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED + "剩余" + time + "分钟");
            }

            throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);
        }
        //如果账号是锁定的，则抛出锁定异常
        if ("Lock".equals(valueOperations.get("accountLocked" + dto.getUsername()))) {
            //抛出账号锁定异常
            long time = valueOperations.getOperations().getExpire("accountLocked" + dto.getUsername()) / 60;
            throw new AccountLockedException(MessageConstant.ACCOUNT_LOCKED + "剩余" + time + "分钟");
        }


        //3.判断账号状态
        if (employee.getStatus() == StatusConstant.DISABLE) {
            throw new AccountStatusException(MessageConstant.AccountStatus_DISABLE);
        }

        //4.生成token令牌
        Map<String, Object> map = new HashMap<>();
        map.put(JwtClaimsConstant.EMP_ID, employee.getId());
        map.put(JwtClaimsConstant.USERNAME, employee.getUsername());
        String token = JwtUtil.createJWT(
                jwtProperties.getAdminSecretKey(),
                jwtProperties.getAdminTtl(),
                map
        );

        //5.封装数据返回.
        EmployeeLoginVO vo = EmployeeLoginVO.builder()
                .id(employee.getId())
                .name(employee.getName())
                .userName(employee.getUsername())
                .token(token)
                .build();

        return Result.success(vo);
    }

    /**
     * 新增员工
     *
     * @param dto
     */
    @Override
    public void add(EmployeeDTO dto) {
        Employee employee = new Employee();
        BeanUtils.copyProperties(dto, employee);
//        employee.setUpdateTime(LocalDateTime.now());
//        employee.setCreateTime(LocalDateTime.now());

        employee.setStatus(1);
//        PasswordConstant.DEFAULT_PASSWORD
        employee.setPassword(bCryptPasswordEncoder.encode(PasswordConstant.DEFAULT_PASSWORD));
//        employee.setUpdateUser(BaseContext.getCurrentId());
//        employee.setCreateUser(BaseContext.getCurrentId());

        employeeMapper.insert(employee);

        return;
    }

    /**
     * 员工分页查询
     *
     * @param dto
     * @return
     */
    @Override
    public PageBean pageQuery(EmployeePageQueryDTO dto) {
        PageHelper.startPage(dto.getPage(),dto.getPageSize());
        Page<Employee> page = employeeMapper.pageQuery(dto);

        return PageBean.builder()
                .total(page.getTotal())
                .records(page.getResult())
                .build();
    }

    /**
     * 启动禁用员工账号
     *
     * @param id
     * @param status
     */
    @Override
    public void startOrStop(Long id, Integer status) {
        Employee employee = Employee.builder()
                .id(id).status(status)
//                .updateUser(BaseContext.getCurrentId())
//                .updateTime(LocalDateTime.now())
                .build();

        //为了兼容以后的功能
        employeeMapper.update(employee);

        return;
    }

    /**
     * 编辑员工信息
     *
     * @param dto
     */
    @Override
    public void update(EmployeeDTO dto) {
        Employee employee = new Employee();
        BeanUtils.copyProperties(dto,employee);
//        employee.setUpdateUser(BaseContext.getCurrentId());
//        employee.setUpdateTime(LocalDateTime.now());

        employeeMapper.update(employee);

        return;
    }

    /**
     * 根据id查询员工
     *
     * @param id
     * @return
     */
    @Override
    public Employee getById(Integer id) {
        Employee employee = employeeMapper.getById(id);

        return employee;
    }

    /**
     * 修改密码
     *
     * @param dto
     */
    @Override
    public void updatePassword(PasswordEditDTO dto) {

        Long currentId = BaseContext.getCurrentId();
        //如果账号无误
        String password = employeeMapper.getPasswordById(currentId);

        //如果与旧密码匹配不上
        if( !password.equals(dto.getOldPassword()) ){
            throw new PasswordErrorException(MessageConstant.PASSWORD_ERROR);
        }
        //修改密码
        Employee employee = Employee.builder()
                .password(dto.getNewPassword())
                .id(currentId)
                .build();
        employeeMapper.update(employee);
        return;
    }

    /**
     * 找到所有员工的信息
     *
     * @return
     */
    @Override
    public List<Employee> getAll() {
        return employeeMapper.getAll();
    }


}
